.syntax unified

#define FLASH_BASE 0x40023c00

#define FLASH_ACR (FLASH_BASE + 0x00)
#define FLASH_KEYR (FLASH_BASE + 0x04)
#define FLASH_OPTKEYR (FLASH_BASE + 0x08)
#define FLASH_SR (FLASH_BASE + 0x0c)
#define FLASH_CR (FLASH_BASE + 0x10)
#define FLASH_OPTCR (FLASH_BASE + 0x14)

.section .vectors
.globl _start
_start:
_flash_init:
	b	flash_init
_flash_erase_all:
	b	flash_erase_all
_flash_erase_page:
	b	flash_erase_page
_flash_write_page:
	b	flash_write_page

.macro fwait, rega, regb
0:
	ldr	\rega, =FLASH_SR
	ldr	\regb, [\rega]
	tst \regb, #(1<<16) // busy
	bne	0b
.endm

.text
flash_init:
	/* unlock the flash controller */
	ldr	r0, =FLASH_KEYR
	ldr r1, =0x45670123
	ldr r2, =0xcdef89ab
	str	r1, [r0]
	str	r2, [r0]
	bx	lr

flash_erase_all:
	ldr	r0, =FLASH_CR
	mov	r1, #(1<<2) // mass erase
	str	r1, [r0]
	orr	r1, #(1<<16) // start
	str	r1, [r0]

	// wait for it to finish
	fwait r0, r1

	bx	lr

flash_erase_page:
	/* calculate the sector */
	sub	r1, r0, #0x08000000
	cmp	r1, #0x10000
	bge	gt64k
lt64k:
	/* sector 0-3 are 16K */
	lsr	r1, #14
	b	starterase
gt64k:
	/* sector 4 is 64k-128k */
	cmp	r1, #0x20000
	bge	gt128k
	mov	r1, #4
	b	starterase
gt128k:
	/* sector 5+ are 128k, starting at 0x20000 */
	lsr	r1, #17
	add	r1, #4

starterase:
	/* set the page erase bit */
	ldr	r2, =FLASH_CR
	lsl	r1, #3			/* sector number */
	orr	r1, #(1<<1)		/* sector erase */
	str	r1, [r2]

	/* start the erase */
	orr	r1, #(1<<16) // start
	str	r1, [r2]

	// wait for it to finish
	fwait r0, r1

	bx	lr

flash_write_page:
	/* set the programming bit */
	ldr	r1, =FLASH_CR
	ldr	r2, =#(2<<8)|(1<<0)
	str	r2, [r1]

	/* start copying data */
	/* r0 holds destination */
	ldr	r1, =0x20002000 /* source */
	add r2, r1, $0x4000  /* end at source */
.Lwriteloop:
	ldr		r12, [r1], #4
	str		r12, [r0], #4

	fwait r3, r4

	cmp		r2, r1
	bne		.Lwriteloop

	bx	lr

.ltorg

